﻿using BSF.Db;
using HuntingFishGame.Domain.Model.WeChat;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using BSF.Enums;
using BSF.Log;
using BSF.ServicesResult;
using BSF.SystemConfig;
using BSF.Tool;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using HuntingFishGame.Domain.BLL.WeChat;
using System.Text.RegularExpressions;
using System.Web.Security;
using System.Xml;
using Bzw.Data;
using HuntingFishGame.Domain.BLL.User;

namespace HuntingFishGame.CustomerApi.Controllers.Monitor
{
    /// <summary>
    /// 微信监听程序API
    /// </summary>
    public class WeixinController : Controller
    {
        #region 基础配置
        /// <summary>
        /// 
        /// </summary>
        public static string Token
        {
            get
            {
                return "lydgame";
                //return XmlHelper.GetXmlNodeValue("/Configs/WXConfig.xml", "/Website/User/token", "shenxinfeng88");
            }
            //set
            //{
            //    XmlHelper.SetXmlNodeValue("/Configs/WXConfig.xml", "/Website/User/token", value.ToString());
            //}
        }
        /// <summary>
        /// 
        /// </summary>
        public static string AppID
        {
            get
            {
                return XmlHelper.GetXmlNodeValue("/Configs/WXConfig.xml", "/Website/User/appid");
            }
            set
            {
                XmlHelper.SetXmlNodeValue("/Configs/WXConfig.xml", "/Website/User/appid", value.ToString());
            }
        }
        /// <summary>
        /// 
        /// </summary>
        public static string AppSecret
        {
            get
            {
                return XmlHelper.GetXmlNodeValue("/Configs/WXConfig.xml", "/Website/User/appsecret");
            }
            set
            {
                XmlHelper.SetXmlNodeValue("/Configs/WXConfig.xml", "/Website/User/appsecret", value.ToString());
            }
        }
        /// <summary>
        /// 
        /// </summary>
        public static string Access_Token
        {
            get
            {
                return WeixinConfig.BaseAccessToken(WeixinType.CertServiceAccount).ParamValue;
                //return XmlHelper.GetXmlNodeValue("/Configs/WXConfig.xml", "/Website/User/access_token");
            }
            //set
            //{
            //    XmlHelper.SetXmlNodeValue("/Configs/WXConfig.xml", "/Website/User/access_token", value.ToString());
            //}
        }

        private static System.Collections.Hashtable err = new System.Collections.Hashtable();
        public WeixinController()
        {
            if (err.Count == 0)
            {
                err.Add("", "");
                err.Add(" -1", "系统繁忙");
                err.Add("0", "请求成功");
                err.Add("40001", "验证失败");
                err.Add("40002", "不合法的凭证类型");
                err.Add("40003", "不合法的OpenID");
                err.Add("40004", "不合法的媒体文件类型");
                err.Add("40005", "不合法的文件类型");
                err.Add("40006", "不合法的文件大小");
                err.Add("40007", "不合法的媒体文件id");
                err.Add("40008", "不合法的消息类型");
                err.Add("40009", "不合法的图片文件大小");
                err.Add("40010", "不合法的语音文件大小");
                err.Add("40011", "不合法的视频文件大小");
                err.Add("40012", "不合法的缩略图文件大小");
                err.Add("40013", "不合法的APPID");
                err.Add("40014", "不合法的access_token");
                err.Add("40015", "不合法的菜单类型");
                err.Add("40016", "不合法的按钮个数");
                err.Add("40017", "不合法的按钮个数");
                err.Add("40018", "不合法的按钮名字长度");
                err.Add("40019", "不合法的按钮KEY长度");
                err.Add("40020", "不合法的按钮URL长度");
                err.Add("40021", "不合法的菜单版本号");
                err.Add("40022", "不合法的子菜单级数");
                err.Add("40023", "不合法的子菜单按钮个数");
                err.Add("40024", "不合法的子菜单按钮类型");
                err.Add("40025", "不合法的子菜单按钮名字长度");
                err.Add("40026", "不合法的子菜单按钮KEY长度");
                err.Add("40027", "不合法的子菜单按钮URL长度");
                err.Add("40028", "不合法的自定义菜单使用用户");
                err.Add("40029", "不合法的oauth_code");
                err.Add("40030", "不合法的refresh_token");
                err.Add("40031", "不合法的openid列表");
                err.Add("40032", "不合法的openid列表长度");
                err.Add("40033", "不合法的请求字符，不能包含\\uxxxx格式的字符");
                err.Add("40035", "不合法的参数");
                err.Add("40038", "不合法的请求格式");
                err.Add("40039", "不合法的URL长度");
                err.Add("40050", "不合法的分组id");
                err.Add("40051", "分组名字不合法");

                err.Add("41001", "缺少access_token参数");
                err.Add("41002", "缺少appid参数");
                err.Add("41003", "缺少refresh_token参数");
                err.Add("41004", "缺少secret参数");
                err.Add("41005", "缺少多媒体文件数据");
                err.Add("41006", "缺少media_id参数");
                err.Add("41007", "缺少子菜单数据");
                err.Add("41008", "缺少oauth code");
                err.Add("41009", "缺少openid");

                err.Add("42001", "access_token超时");
                err.Add("42002", "refresh_token超时");
                err.Add("42003", "oauth_code超时");

                err.Add("43001", "需要GET请求");
                err.Add("43002", "需要POST请求");
                err.Add("43003", "需要HTTPS请求");
                err.Add("43004", "需要接收者关注");
                err.Add("43005", "需要好友关系");

                err.Add("44001", "多媒体文件为空");
                err.Add("44002", "POST的数据包为空");
                err.Add("44003", "图文消息内容为空");
                err.Add("44004", "文本消息内容为空");

                err.Add("45001", "多媒体文件大小超过限制");
                err.Add("45002", "消息内容超过限制");
                err.Add("45003", "标题字段超过限制");
                err.Add("45004", "描述字段超过限制");
                err.Add("45005", "链接字段超过限制");
                err.Add("45006", "图片链接字段超过限制");
                err.Add("45007", "语音播放时间超过限制");
                err.Add("45008", "图文消息超过限制");
                err.Add("45009", "接口调用超过限制");
                err.Add("45010", "创建菜单个数超过限制");
                err.Add("45015", "回复时间超过限制");
                err.Add("45016", "系统分组，不允许修改");
                err.Add("45017", "分组名字过长");
                err.Add("45018", "分组数量超过上限");

                err.Add("46001", "不存在媒体数据");
                err.Add("46002", "不存在的菜单版本");
                err.Add("46003", "不存在的菜单数据");
                err.Add("46004", "不存在的用户");

                err.Add("47001", "解析JSON/XML内容错误");

                err.Add("48001", "api功能未授权");
                err.Add("50001", "用户未授权该api");
                //err["40001"].ToString();
            }
        }
        #endregion

        #region 验证消息真实性
        /// <summary>
        /// 验证消息真实性
        /// </summary>
        /// <param name="signature">微信加密签名，signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。</param>
        /// <param name="timestamp">时间戳</param>
        /// <param name="nonce">随机数</param>
        /// <param name="echostr">随机字符串</param>
        /// <returns></returns>
        /// <remark> 
        /// 开发者通过检验signature对请求进行校验（下面有校验方式）。若确认此次GET请求来自微信服务器，请原样返回echostr参数内容，则接入生效，成为开发者成功，否则接入失败。 
        /// </remark>
        [HttpGet]
        public ActionResult Index(string signature, string timestamp, string nonce, string echostr)
        {
            //if (!SignHelper.CheckSignature(Token, timestamp, nonce, signature))
            //{
            //    return Content("签名错误:" + signature);
            //}
            //ErrorLog.Write("signature:" + signature + ",timestamp:" + timestamp + ",nonce:" + nonce + ",echostr:" + echostr, null);

            echostr = Valid();
            return Content(echostr);
            //如果要测试微信接口，请先注释下面的代码，然后把View/Weixin/Index.cshtml修改为其他的名字
            //return View();//要浏览页面，取消该注释
        }
        #endregion

        #region 验证微信签名 保持默认即可
        /// <summary>
        /// 第一次验证url有效性，微信发起GET请求
        /// </summary>
        private string Valid()
        {
            //获取微信发送给服务器的随机字符串
            string echoStr = Request.QueryString["echoStr"].ToString();
            //判断签名通过，向微信服务器原样返回随机字符串
            if (CheckSignature())
            {
                if (!string.IsNullOrEmpty(echoStr))
                {
                    return echoStr;
                }
            }
            return string.Empty;
        }

        /// <summary>
        /// 验证微信签名
        /// </summary>
        /// * 将token、timestamp、nonce三个参数进行字典序排序
        /// * 将三个参数字符串拼接成一个字符串进行sha1加密
        /// * 开发者获得加密后的字符串可与signature对比，标识该请求来源于微信。
        /// <returns></returns>
        private bool CheckSignature()
        {
            string signature = Request.QueryString["signature"].ToString();//微信加密签名
            string timestamp = Request.QueryString["timestamp"].ToString();//时间戳
            string nonce = Request.QueryString["nonce"].ToString();//随机数
            string[] arrTmp = { Token, timestamp, nonce };
            Array.Sort(arrTmp);     //字典排序
            string tmpStr = string.Join("", arrTmp);
            tmpStr = FormsAuthentication.HashPasswordForStoringInConfigFile(tmpStr, "SHA1");//加密
            tmpStr = tmpStr.ToLower();

            //与微信加密判断，一致返回真
            if (tmpStr == signature)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        #endregion


        #region 发送被动响应消息

        /// <summary>
        /// 发送被动响应消息
        /// 商家给用户回复文字，图片消息的时候，会不会出发被动响应时间，如果会，则插入消息的时候就要判断是收到的消息还是回复的消息（不会触发）
        /// 上传图片，视频等文件时，也不会触发被动响应事件
        /// </summary>
        //参数：
        //signature:微信加密签名，signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
        //timestamp:时间戳 
        //nonce:随机数
        [HttpPost]
        public ActionResult Index(string signature, string timestamp, string nonce)//, System.IO.Stream streams = null
        {
            //if (!SignHelper.CheckSignature(Token, timestamp, nonce, signature))
            //{
            //    WeComm.Domain.PostMessage pmxp = PubBLL.Receive(Request.InputStream);
            //    PubBLL.ReplyText(pmxp.FromUserName, pmxp.ToUserName, DateTime.Now, string.Format("签名错误:{0},timestamp:{1},nonce:{2}", signature, timestamp, nonce), 0);
            //    return Content("签名错误:" + signature);
            //}
            //ErrorLog.Write("signature:" + signature + ",timestamp:" + timestamp + ",nonce:" + nonce, null);
            #region 取xml数据
            ////读取远程xml文件
            //var xmlDoc = XmlHelper.ProcessItem(@"http://localhost/location.xml");
            //string xml = XmlHelper.ConvertXmlToString(xmlDoc);

            ////1.utf-8编码格式读取
            ////Stream inputStream = System.Web.HttpContext.Current.Request.InputStream;
            ////long pos = inputStream.Position;
            ////inputStream.Position = 0;
            ////byte[] buffer = new byte[inputStream.Length];
            ////inputStream.Read(buffer, 0, buffer.Length);
            ////inputStream.Position = pos;
            ////string xml = System.Text.Encoding.UTF8.GetString(buffer);
            ////xml = Server.UrlDecode(xml);
            ////2.直接读取
            ////StreamReader reader = new StreamReader(Request.InputStream);
            ////string xml = reader.ReadToEnd();
            #endregion
            //接收数据
            //ToUserName:接收方帐号（收到的OpenID）
            //FromUserName:开发者微信号
            //CreateTime:消息创建时间 （整型）
            //MsgType:text
            //Content:回复的消息内容（换行：在content中能够换行，微信客户端就支持换行显示） 
            PostMessage pm = null;
            //if (streams != null)
            //{
            //    pm = PubBLL.Receive(streams);
            //}
            //else
            //{
            pm = PubBLL.Receive(Request.InputStream);
            //}
            //Utility.Log(pm.MsgType);
            //CommLog.Write("0.1接收内容:" + JsonConvert.SerializeObject(pm));
            string sendxml = "";
            switch (pm.MsgType)
            {
                case "text":
                    #region 自动回复推送消息

                    #region Test
                    //if (pm.Content == "?" || pm.Content == "？")
                    //    sendxml = PubBLL.ReplyText(pm.FromUserName, pm.ToUserName, DateTime.Now, SubscribeDocument());
                    //else if (pm.Content == "1")
                    //{
                    //    StringBuilder sb = new StringBuilder();
                    //    sb.Append("近期点呀点有如下活动：").Append("\n");
                    //    sb.Append("<a href='http://218.244.135.200:8004/StoreActivity/Activity/one'>1元抢购水果大礼包</a>").Append("\n\n");

                    //    sendxml = PubBLL.ReplyText(pm.FromUserName, pm.ToUserName, DateTime.Now, sb.ToString());
                    //    //sendxml = PubBLL.ReplyText(pm.FromUserName, pm.ToUserName, DateTime.Now, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), 0);
                    //}
                    //else if (pm.Content == "2")
                    //{
                    //    StringBuilder sb = new StringBuilder();
                    //    sb.Append("获得优惠券的方式有2种：").Append("\n");
                    //    sb.Append("（1）注册时输入好友的邀请码，可以直接获得2张价值5元的优惠券，总价值达10元；").Append("\n");
                    //    sb.Append("（2）成功邀请一个好友加入点呀点，会获得一张5元优惠券；").Append("\n");
                    //    sb.Append("<a href='http://218.244.135.200:8004/Invite/Home'>详细内容查看</a>").Append("\n");

                    //    sendxml = PubBLL.ReplyText(pm.FromUserName, pm.ToUserName, DateTime.Now, sb.ToString());
                    //    //sendxml = PubBLL.ReplyText(pm.FromUserName, pm.ToUserName, DateTime.Now, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), 0);
                    //}
                    ////else if (pm.Content == "1")
                    ////{
                    ////    StringBuilder sb = new StringBuilder();
                    ////    sb.Append("近期点呀点有如下活动，回复查看详情：").Append("\n");
                    ////    sb.Append("11、<a href='http://218.244.135.200:8004/StoreActivity/Activity/one'>1元抢购水果大礼包</a>").Append("\n\n");

                    ////    ReplyNewsArticle _obj = new ReplyNewsArticle();
                    ////    _obj.Title = "1元抢购水果大礼包";
                    ////    _obj.Description = "粗大事啦，1元大礼包11.28上午10点起大量派送！仅需1元，即可得红富士苹果2个，赣南脐橙2个，连州水晶梨2个";
                    ////    _obj.PicUrl = "http://218.244.135.200:8004/Content/images/shui.png";
                    ////    _obj.Url = "http://218.244.135.200:8004/StoreActivity/Activity/one";
                    ////    List<ReplyNewsArticle> list = new List<ReplyNewsArticle>();
                    ////    list.Add(_obj);
                    ////    sendxml = PubBLL.ReplyNews(pm.FromUserName, pm.ToUserName, DateTime.Now, list);
                    ////    //sendxml = PubBLL.ReplyText(pm.FromUserName, pm.ToUserName, DateTime.Now, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), 0);
                    ////}
                    ////else if (pm.Content == "2")
                    ////    sendxml = PubBLL.ReplyText(pm.FromUserName, pm.ToUserName, DateTime.Now, "shenxinfeng:" + Access_Token, 0);
                    ////else if (pm.Content == "好人")
                    ////{
                    ////    sendxml = PubBLL.ReplyText(pm.FromUserName, pm.ToUserName, DateTime.Now, "你也是一个好人。<a href=\"http://www.baidu.com/\">aaaaaaaaaaaa</a>", 0);
                    ////}
                    ////else if (pm.Content == "验证")
                    ////{
                    ////    string url = "http://" + this.Request.Url.Host + VirtualPathUtility.ToAbsolute(Url.Action("Login", "Crm", new { username = pm.FromUserName, time = pm.CreateTime }));
                    ////    sendxml = PubBLL.ReplyText(pm.FromUserName, pm.ToUserName, DateTime.Now, "为了确保您的账户信息安全，请先验证一次身份，即可使用以下功能：……与我对话，可发现更多功能。<a href=\"" + url + "\">点击验证身份</a>", 0);
                    ////}
                    ////else if (pm.Content == "图文")
                    ////{
                    ////    List<WeComm.Domain.ReplyNewsArticle> Articles = new List<WeComm.Domain.ReplyNewsArticle>();
                    ////    Articles.Add(new WeComm.Domain.ReplyNewsArticle()
                    ////    {
                    ////        Title = "测试信息1",
                    ////        Description = "这是第一个测试信息",
                    ////        PicUrl = "http://i2.sinaimg.cn/bb/2010/1104/201011494947.jpg",
                    ////        Url = "http://kid.baby.sina.com.cn/2010-11-04/095346331.html"
                    ////    });
                    ////    Articles.Add(new WeComm.Domain.ReplyNewsArticle()
                    ////    {
                    ////        Title = "测试信息2",
                    ////        Description = "这是第二个测试信息",
                    ////        PicUrl = "http://i2.sinaimg.cn/kid/2009-07-24/U303P205T1D37145F96DT20090724114329.jpg",
                    ////        Url = "http://kid.baby.sina.com.cn/2009-07-24/114337145.html"
                    ////    });
                    ////    sendxml = PubBLL.ReplyNews(pm.FromUserName, pm.ToUserName, DateTime.Now, Articles, 0);
                    ////}
                    #endregion

                    #region 自动回复推送消息(推送到多客服，记录到数据库)
                    try
                    {
                        bool isAutoReply = true;
                        bool isError = false;
                        #region 正则匹配解锁指令
                        //C# 正则表达式类 Match类和Group类 http://www.cnblogs.com/zwwhnly/archive/2012/12/18/2823670.html
                        //C# 中使用正则表达式 Regex.Matches方法的几个应用 http://blog.csdn.net/gishero/article/details/5244463
                        //正则表达式测试工具 http://tool.oschina.net/regex/
                        //正则测试 http://tool.chinaz.com/regex/
                        Regex rg = new Regex("js#[^#]+#[^#]+#", RegexOptions.Multiline | RegexOptions.Singleline);
                        Match m = rg.Match(pm.Content);
                        if (m.Success)
                        {
                            isError = true;
                        }
                        else
                        {
                            //定义一个模式字符串,不仅仅是纯文本，还可以是正则表达式  
                            string pattern = "js#[^#]+#[^#]+";
                            MatchCollection matches = Regex.Matches(
                                pm.Content,
                                pattern,
                                RegexOptions.IgnoreCase |         //忽略大小写  
                                RegexOptions.ExplicitCapture |    //提高检索效率  
                                RegexOptions.RightToLeft          //从左向右匹配字符串  
                            );
                            //Console.WriteLine("从右向左匹配字符串：");
                            //foreach (Match NextMatch in matches)
                            //{
                            //    Console.Write("匹配的位置：{0,2} ", NextMatch.Index);
                            //    Console.Write("匹配的内容：{0,2} ", NextMatch.Value);
                            //    Console.Write("/n");
                            //}  

                            if (pm.Content.ToLower().StartsWith("js#") && matches.Count == 1)
                            {
                                #region 指定格式解锁:JS#用户帐号#游戏银行密码

                                string[] temStrings = pm.Content.Split('#');
                                if (temStrings[0].ToLower().Equals("js") && temStrings.Length == 3)
                                {
                                    //TODO 密码要做长度，特殊字符，安全性验证(必须包含大小写英文+数字等)
                                    //[0-9a-zA-Z]{4,23} 匹配字符或字母4-23位，不考虑全为数字和全为字符情况。
                                    //匹配特殊字符((?=[\x21-\x7e]+)[^A-Za-z0-9])
                                    Regex regSpecialCharacter = new Regex("[^A-Za-z0-9]", RegexOptions.Multiline | RegexOptions.Singleline);
                                    Match mcharMatch1 = regSpecialCharacter.Match(temStrings[1]);
                                    Match mcharMatch2 = regSpecialCharacter.Match(temStrings[2]);
                                    //密码由6-20个英文字母和数字组成
                                    if (temStrings[1].Length < 6 || temStrings[2].Length < 6)
                                    {
                                        sendxml = PubBLL.ReplyText(pm.FromUserName, pm.ToUserName, DateTime.Now, "账号或密码太短了");
                                        isError = false;
                                        isAutoReply = false;
                                    }
                                    else if (temStrings[1].Length > 12 || temStrings[2].Length > 20)
                                    {
                                        sendxml = PubBLL.ReplyText(pm.FromUserName, pm.ToUserName, DateTime.Now, "账号或密码太长了");
                                        isError = false;
                                        isAutoReply = false;
                                    }
                                    else if (mcharMatch1.Success || mcharMatch2.Success)
                                    {
                                        sendxml = PubBLL.ReplyText(pm.FromUserName, pm.ToUserName, DateTime.Now, "账号或密码包含特殊字符");
                                        isError = false;
                                        isAutoReply = false;
                                    }
                                    else
                                    {
                                        //插入绑定的账号 pm.FromUserName->用户的OpenId,pm.ToUserName->当前公众号Id
                                        long id = WechatAccountBindBLL.Add(BSFConfig.MainConnectString, new WechatAccountBindModel()
                                        {
                                            BatchNumber = Guid.NewGuid().ToString("N"),
                                            OrderNumber = "0",
                                            AccountNumber = temStrings[1],
                                            UpdatePassword = temStrings[2],
                                            OpenId = pm.FromUserName,
                                            IsChecked = true,
                                            Status = 0
                                        });
                                        //var userModel = UserBLL.GetInfo(BSFConfig.GameConnectString, temStrings[1]);
                                        //根据游戏账号，游戏银行密码解锁接口（公众平台里面回复时使用）
                                        //提交给游戏平台解锁，解锁成功后，更新状态
                                        int state = UserPasswordBLL.UnBindPc(BSFConfig.GameConnectString, temStrings[1], temStrings[2]);
                                        string tempmsg = string.Empty;
                                        switch (state)
                                        {
                                            case 6:
                                                tempmsg = "账号或密码错误";
                                                break;
                                            case 4:
                                                tempmsg = "未锁定机器";
                                                break;
                                            case 3:
                                                tempmsg = "解锁成功";
                                                break;
                                            default:
                                                tempmsg = "解锁失败";
                                                break;
                                        }
                                        //成功
                                        WechatAccountBindBLL.UpdateStatus(BSFConfig.MainConnectString, id,
                                            state == 3 ? BSFAPICode.Success : BSFAPICode.NormalError, tempmsg);

                                        sendxml = PubBLL.ReplyText(pm.FromUserName, pm.ToUserName, DateTime.Now,
                                            state == 3 ? "解锁成功" : tempmsg);
                                        isError = false;
                                        isAutoReply = false;
                                    }

                                }
                                else
                                {
                                    isError = true;
                                }

                                #endregion
                            }
                            else
                            {
                                isError = false;
                            }
                        }
                        if (isError)
                        {
                            sendxml = PubBLL.ReplyText(pm.FromUserName, pm.ToUserName, DateTime.Now, "指令有误，请重新输入");
                            isAutoReply = false;
                        }
                        #endregion

                        #region 原来的密码逻辑
                        /*
                         * 1.判断输入的是否是序号，如果不是序号，则根据OpenId+isChecked=1查询最后一条数据。如果超过3分钟，则继续查询自动回复表。如果没有超过3分钟，则到第6步...
                         * 2.根据OpenId+序号,获取绑定账号。如果没有数据，则继续查询自动回复表。
                         * 3.查到数据后，判断是否超过时间，如果超过，则继续查询自动回复表。
                         * 4.如果没有超过回复时间，则更新isChecked=1,UpdateTime=DateTime.Now。然后回复用户输入游戏银行密码。
                         * 5.输入密码后，根据OpenId+isChecked=1查询最后一条数据。如果超过3分钟，则继续查询自动回复表。
                         * 6.如果没有超过回复时间，则提交给游戏平台解锁。可以加个确认逻辑，用户回复Y之后提交游戏平台进行修改。
                         * 7.注意：修改成功后，把isChecked=1的数据时间改成5分钟以外，同一批次其他未选中的改成6分钟以外，同时数据修改状态为已使用。
                         * 8.注意：密码要做长度，特殊字符，安全性验证。
                         * **/
                        //1.回复的是序号，2.回复的是游戏账号密码
                        //pm.FromUserName->用户的OpenId,pm.ToUserName->当前公众号Id
                        //var currentAccountBind = WechatAccountBindBLL.GetLastAccountBind(BSFConfig.MainConnectString, pm.FromUserName, pm.Content);
                        //if (currentAccountBind != null)
                        //{
                        //    TimeSpan ts = dtNow.Subtract(currentAccountBind.UpdateTime);
                        //    //3分钟以内的回复
                        //    if (ts.TotalSeconds <= 3 * 60)
                        //    {
                        //        isAutoReply = false;
                        //        //TODO 1.更新选定序号的账号isChecked=1,2.回复用户输入游戏银行密码
                        //        sendxml = PubBLL.ReplyText(pm.FromUserName, pm.ToUserName, DateTime.Now, "请输入游戏银行密码");
                        //    }
                        //}
                        #endregion
                        if (isAutoReply)
                        {
                            #region 自动回复消息
                            var obj = AutoReplyBLL.GetModelDetail(BSFConfig.MainConnectString, "f_keyword", pm.Content.Replace("<p>", "").Replace("</p>", ""));
                            if (obj != null && !string.IsNullOrEmpty(obj.content))
                            {
                                sendxml = PubBLL.ReplyText(pm.FromUserName, pm.ToUserName, DateTime.Now, obj.content);
                                //CommLog.Write("2.xml:" + sendxml);//写common日志
                            }
                            else
                            {
                                string timeinterval = BSFConfig.AutoDKFTimeInterval;
                                List<string> listtime = timeinterval.Trim().Split(new char[] { '-' }, StringSplitOptions.RemoveEmptyEntries).ToList();
                                DateTime starttime = Convert.ToDateTime(listtime[0]);
                                DateTime endtime = Convert.ToDateTime(listtime[1]);
                                //DateTime d1 = Convert.ToDateTime("09:30");//转换为时间格式，自动补全为当前日期
                                //if(DateTime.Now.Hour>=9 && DateTime.Now.Hour<=20)
                                if (DateTime.Now >= starttime && DateTime.Now <= endtime)
                                {
                                    sendxml = PubBLL.DKFReplyNews(pm.FromUserName, pm.ToUserName, DateTime.Now);//转发到多客服系统
                                    //CommLog.Write("3.xml:" + sendxml);//写common日志
                                }
                                else
                                {
                                    StringBuilder sb = new StringBuilder();
                                    sb.Append(BSFConfig.AutoDKFText);
                                    //sb.Append("亲爱的点友，感谢您的反馈。").Append("\n");
                                    //sb.Append("为更快更及时受理您的需求，请直接致电：4001618618，或加在线QQ：4008261418。").Append("\n");
                                    //sb.Append("PS：客服软妹纸糯糯的声音已完爆志玲姐姐哦！么么哒~");
                                    sendxml = PubBLL.ReplyText(pm.FromUserName, pm.ToUserName, DateTime.Now, sb.ToString());
                                    //CommLog.Write("4.xml:" + sendxml);//写common日志
                                }
                            }
                            #endregion
                        }

                        #region 添加文本信息
                        ////先根据FromUserName(发送方帐号（一个OpenID）)查询得到所在分组，然后在保存消息信息
                        //var item = new PostMessageModel();
                        //item.f_msgid = pm.MsgId;
                        //item.f_tousername = pm.ToUserName;
                        //item.f_uid = pm.FromUserName;//发送方帐号（一个OpenID）
                        //item.f_msgtype = pm.MsgType;
                        //item.f_content = pm.Content;
                        //item.f_reply = 0;//是否是回复（0-接收的消息，1-回复的消息）
                        //item.f_answered = 0;//是否已回复（0-未回复，1-已回复,2-已忽略，3-取消关注后更新的状态，4-自动回复关键词更新的状态）
                        //DateTime dtnow = PubBLL.GetTime(LibConvert.ObjToStr(pm.CreateTime.ToString()));//转化为DateTime
                        ////DateTime dt_1970 = new DateTime(1970, 1, 1);
                        //item.f_createtime = dtnow;


                        //#region 查询是否是自动回复
                        //string query = string.Format(" and f_keyword='{0}' and f_sfdj=0 ", pm.Content);
                        ////如果自动回复表里面存在，则回复状态更新为已回复
                        //int rowcount = AutoReplyBLL.TotalItems(BSFConfig.MainConnectString, string.Empty, query);
                        //if (rowcount > 0)
                        //    item.f_answered = 4;//是否已回复（0-未回复，1-已回复,2-已忽略，3-取消关注后更新的状态，4-自动回复关键词更新的状态）
                        //#endregion

                        ////TODO 插入消息内容
                        ////bool add_status = PostMessageBLL.Add(BSFConfig.MainConnectString, item);
                        #endregion
                    }
                    catch (Exception ex)
                    {
                        ErrorLog.Write("自动回复消息失败:" + ex.Message, ex);
                        StringBuilder sb = new StringBuilder();
                        sb.Append(BSFConfig.AutoDKFText + "^_^");
                        //sb.Append("亲爱的点友，感谢您的反馈。").Append("\n");
                        //sb.Append("为更快更及时受理您的需求，请直接致电：4001618618，或加在线QQ：4008261418。").Append("\n");
                        //sb.Append("PS：客服软妹纸糯糯的声音已完爆志玲姐姐哦！么么哒~");
                        sendxml = PubBLL.ReplyText(pm.FromUserName, pm.ToUserName, DateTime.Now, sb.ToString());
                    }
                    #endregion

                    #endregion
                    break;
                case "image":
                    //sendxml = PubBLL.ReplyText(pm.FromUserName, pm.ToUserName, DateTime.Now, "图片地址为：" + pm.PicUrl, 0);
                    break;
                case "voice":
                    #region 添加语音信息
                    #endregion
                    break;
                case "video":
                    #region 添加视频信息
                    //上传的多媒体文件有格式和大小限制，如下：
                    //图片（image）: 1M，支持JPG格式
                    //语音（voice）：2M，播放长度不超过60s，支持AMR\MP3格式
                    //视频（video）：10MB，支持MP4格式
                    //缩略图（thumb）：64KB，支持JPG格式 
                    //先根据FromUserName(发送方帐号（一个OpenID）)查询得到所在分组，然后在保存消息信息
                    #endregion
                    break;
                case "location":
                    #region 添加地理位置信息
                    #endregion
                    break;
                case "link":
                    #region 添加链接消息
                    #endregion
                    break;
                case "event":
                    string sResult = GetEventMsg(pm);
                    if (!string.IsNullOrEmpty(sResult))
                        sendxml = PubBLL.ReplyText(pm.FromUserName, pm.ToUserName, DateTime.Now, sResult);
                    break;
                default:
                    break;
            }
            //XmlDocument xml = new XmlDocument();
            //xml.Load(Request.InputStream);
            //string s = xml.OuterXml;
            //xml.GetElementsByTagName("MsgType")[0].InnerText
            //XDocument rxml = XDocument.Load(Request.InputStream);
            //List<ApiClient.ParmField> parmList = new List<ApiClient.ParmField>();
            //parmList.Add(new ApiClient.StringField("xml", Server.HtmlEncode(rxml.ToString())));
            //ApiClient.ApiResult result = Models.WebChatPub.InvokeApi(this, parmList);
            //XDocument sxml = Models.WebChatPub.SendXml(this, rxml, result.responseObject["response"]);
            //string sendxml = Server.HtmlDecode(sxml.ToString());
            return Content(sendxml, "text/plain", Encoding.UTF8);//第二个参数就是：MIME类型
        }
        #region GetEventMsg
        private string GetEventMsg(PostMessage pm)
        {
            string sResult = string.Empty;
            #region 接收事件消息
            switch (pm.Event.ToLower())
            {
                case "scan":
                    {
                        try
                        {
                            SaveUserInfo(pm);
                            //sResult = SubscribeDocument();
                            sResult = EventCase(pm);
                        }
                        catch (Exception ex)
                        {
                            sResult = SubscribeDocument() + "^_^";
                        }
                        break;
                    }
                case "subscribe":
                    {
                        try
                        {
                            //if (!string.IsNullOrEmpty(pm.Ticket))
                            //{
                            //    #region 移动用户所在分组
                            //    /*
                            //     * 1.根据场景id获取商户分组id
                            //       2.用户移到对应的商户分组
                            //     * **/
                            //    //string scene_id = pm.EventKey.Replace("qrscene_", "");
                            //    //string to_groupid = "115";
                            //    ////给用户分到相应的分组
                            //    //ReturnCodeModel _model = PubBLL.MoveGroup(pm.FromUserName, to_groupid.ToString(), Access_Token);
                            //    ////var json = _model.GetJSON();
                            //    ////var _groupmodel = GetGroupByID(Convert.ToInt32(to_groupid));
                            //    #endregion
                            //    sResult = "用户未关注时，进行关注后的事件推送";
                            //}
                            //else
                            //{
                            //    sResult = "订阅";
                            //}

                            SaveUserInfo(pm);
                            //sResult = SubscribeDocument();
                            if (!string.IsNullOrEmpty(pm.EventKey) && pm.EventKey.Contains("qrscene_"))
                            {
                                sResult = EventCase(pm);
                            }
                            else
                            {
                                sResult = SubscribeWelcomeWord();
                            }
                        }
                        catch (Exception ex)
                        {
                            sResult = SubscribeDocument() + "^_^";
                        }
                        break;
                    }
                case "unsubscribe":
                    //sResult = "取消订阅";
                    break;
                case "location":
                    {
                        //sResult = "上报地理位置事件";
                        break;
                    }
                //自定义菜单事件
                case "click":
                    {
                        //联系客服(人工客服)
                        if (pm.EventKey.ToLower().Equals("click_customerservice"))
                        {
                            sResult = BSFConfig.AutolLXKFText;
                        }
                        else if (pm.EventKey.ToLower().Equals("click_machineunlock"))
                        {
                            //List<string> userAccountList = new List<string>()
                            //{
                            //    "shenxf1","shenxf2","shenxf3"
                            //};
                            List<string> userAccountList = new List<string>();
                            //插入绑定的账号 pm.FromUserName->用户的OpenId,pm.ToUserName->当前公众号Id
                            int count = 0;
                            var userList = WxCodeBLL.GetList(BSFConfig.GameConnectString, pm.FromUserName, 1, 20, out count);
                            if (userList != null && userList.Any())
                            {
                                userAccountList = userList.Select(p => p.UserName).ToList();
                            }
                            if (userAccountList.Any())
                            {
                                #region 指定格式解锁:JS#用户帐号#游戏银行密码
                                sResult = "你当前绑定的账号为:\n";
                                //KeyValuePair<T,K>
                                int number = 1;
                                //移除空值
                                userAccountList.RemoveAll(p => p == "");
                                foreach (var item in userAccountList)
                                {
                                    sResult += string.Format("{0}.{1}\n", number.ToString(), item);
                                    //Console.WriteLine(kv.Key + kv.Value);
                                }
                                sResult += "输入以下指令可以解锁:js#账号#银行密码";
                                #endregion
                                #region 原有逻辑:绑定1个账号，提示输入密码。绑定多个账号，提示选择账号，然后在输入密码。没有绑定账号，提示未绑定游戏账号。
                                //if (userAccountList.Count > 1)
                                //{
                                //    Dictionary<int, string> dict = new Dictionary<int, string>();
                                //    int number = 1;
                                //    string batchNumber = Guid.NewGuid().ToString("N");
                                //    foreach (var item in userAccountList)
                                //    {
                                //        //插入绑定的账号 pm.FromUserName->用户的OpenId,pm.ToUserName->当前公众号Id
                                //        WechatAccountBindBLL.Add(BSFConfig.MainConnectString, new WechatAccountBindModel()
                                //        {
                                //            BatchNumber = batchNumber,
                                //            OrderNumber = number.ToString(),
                                //            AccountNumber = item,
                                //            UpdatePassword = "",
                                //            OpenId = pm.FromUserName,
                                //            IsChecked = false
                                //        });
                                //        dict.Add(number, item);
                                //        number++;
                                //    }
                                //    sResult = "你当前绑定的账号为:\n";
                                //    //KeyValuePair<T,K>
                                //    foreach (KeyValuePair<int, string> kv in dict)
                                //    {
                                //        sResult += string.Format("{0}.{1}\n", kv.Key, kv.Value);
                                //        //Console.WriteLine(kv.Key + kv.Value);
                                //    }
                                //    sResult += "请输入需要修改的账号序号";
                                //}
                                //else
                                //{
                                //    //插入绑定的账号 pm.FromUserName->用户的OpenId,pm.ToUserName->当前公众号Id
                                //    WechatAccountBindBLL.Add(BSFConfig.MainConnectString, new WechatAccountBindModel()
                                //    {
                                //        BatchNumber = batchNumber,
                                //        OrderNumber = "1",
                                //        AccountNumber = userAccountList.FirstOrDefault(),
                                //        UpdatePassword = "",
                                //        OpenId = pm.FromUserName,
                                //        IsChecked = true
                                //    });
                                //    sResult += "请输入游戏银行密码";
                                //}
                                #endregion
                            }
                            else
                            {
                                sResult = "您的微信未绑定游戏账号";
                            }
                        }
                        //sResult = "在使用点呀点的过程中，遇到任何问题都可以联系我们的客服，客服电话4008261418";
                        //sResult = "点击菜单拉取消息时的事件推送";
                        break;
                    }
                case "view":
                    {
                        //sResult = "点击菜单跳转链接时的事件推送";
                        break;
                    }
                case "scancode_push":
                    {
                        //sResult = "扫码推事件的事件推送";
                        break;
                    }
                case "scancode_waitmsg":
                    {
                        //sResult = "扫码推事件且弹出“消息接收中”提示框的事件推送";
                        break;
                    }
                case "pic_sysphoto":
                    {
                        //sResult = "弹出系统拍照发图的事件推送";
                        break;
                    }
                case "pic_photo_or_album":
                    {
                        //sResult = "弹出拍照或者相册发图的事件推送";
                        break;
                    }
                case "pic_weixin":
                    {
                        //sResult = "弹出微信相册发图器的事件推送";
                        break;
                    }
                case "location_select":
                    {
                        //sResult = "弹出地理位置选择器的事件推送";
                        break;
                    }
            }
            #endregion
            return sResult;
        }
        /// <summary>
        /// 获取帮助菜单文档
        /// </summary>
        /// <returns></returns>
        private string HelpDocument()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("HI，请回复数字，选择服务").Append("\n\n");
            sb.Append("1. 当前时间").Append("\n");
            sb.Append("2. 天气信息").Append("\n");
            sb.Append("3. 聊天唠嗑").Append("\n");
            sb.Append("n. 更多服务开发中...").Append("\n");
            sb.Append("回复【?】显示此帮助菜单");
            return sb.ToString();
        }
        /// <summary>
        /// 获取关注后的自动回复
        /// </summary>
        /// <returns></returns>
        private string SubscribeDocument()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("谢谢关注，我是点点，为了答谢粉丝，我们给您准备了很多惊喜");
            //sb.Append("谢谢关注，我是点点，为了答谢粉丝，我们给您准备了很多惊喜，您可以回复数字（如“1”“2”）获取服务信息：").Append("\n");
            //sb.Append("1. 最新活动").Append("\n");
            //sb.Append("2. 服务介绍").Append("\n");
            //sb.Append("回复【?】显示此帮助菜单");
            return sb.ToString();
        }
        /// <summary>
        /// 保存用户信息
        /// </summary>
        /// <param name="pm"></param>
        /// <returns></returns>
        private void SaveUserInfo(PostMessage pm)
        {
            #region 保存关注用户数据

            //获取用户信息
            var jsonText = PubBLL.GetUserInfo(pm.FromUserName, LangType.zh_CN, Access_Token);
            if (jsonText.IndexOf("errcode", StringComparison.OrdinalIgnoreCase) > 0)
            {
            }
            else
            {
                JObject jo = (JObject)JsonConvert.DeserializeObject(jsonText);
                //JObject.Parse(jsonText);
                string nickname = string.Empty;
                if (jo.Property("nickname") == null || jo.Property("nickname").ToString() == "")
                {
                }
                else
                {
                    nickname = jo["nickname"].ToString();
                }
                WechatFollowModel model = new WechatFollowModel();
                //保存到本地数据库
                model.AppId = WeixinConfig.AppId(WeixinType.CertServiceAccount);
                model.OpenId = pm.FromUserName;
                model.OauthScope = "snsapi_userinfo";
                model.IsAuth = model.OauthScope.Contains("snsapi_userinfo") == true ? true : false;
                model.IsSubscribe = true; //关注
                DateTime dtnow = PubBLL.GetTime(LibConvert.ObjToStr(jo["subscribe_time"].ToString()));
                //转化为DateTime
                model.SubscribeTime = dtnow;
                DateTime dt_1970 = new DateTime(1970, 1, 1);
                model.UnSubscribeTime = dt_1970;
                model.NickName = nickname;
                model.Sex = LibConvert.ObjToInt(jo["sex"].ToString());
                model.Province = jo["province"].ToString();
                model.City = jo["city"].ToString();
                model.Country = jo["country"].ToString();
                //model.f_language = jo["language"].ToString();
                //model.f_groupid = "defaultgroup"; //刚关注的用户分到默认组
                model.HeadImgUrl = jo["headimgurl"].ToString();
                model.UnionId = "";
                model.Privilege = "";
                WeChatFollowBLL.Add(BSFConfig.MainConnectString, model);
            }

            #endregion
        }
        #endregion

        #region 操作文本消息 + void eventCase(XmlElement root)
        /// <summary>
        /// 操作文本消息
        /// </summary>
        /// <param name="xmlMsg"></param>
        private string EventCase(PostMessage xmlMsg)//ExmlMsg xmlMsg
        {
            string returnValue = "接收到EventKey：" + xmlMsg.EventKey + ". ";//存储过程的返回值
            //long nowtime = LibConvert.DateTimeToInt(DateTime.Now);//int nowtime = ConvertDateTimeInt(DateTime.Now);
            string msg = "";//返回给微信的值
            string keyContent = "";
            if (!string.IsNullOrEmpty(xmlMsg.EventKey))//判断事件的key值 例如:key值为qrscene_9955,888888或者9955,888888
            {
                string[] keyContents = xmlMsg.EventKey.Split(',');
                if (keyContents.Length == 2)
                {
                    //获取得到9955【用户编码】
                    if (keyContents[0].Contains("qrscene_"))
                    {
                        keyContent = keyContents[0].Split('_')[1];
                    }
                    else
                    {
                        keyContent = keyContents[0];
                    }

                    //第二个参数【验证码】不为空
                    if (!string.IsNullOrEmpty(keyContent) && !string.IsNullOrEmpty(keyContents[1]))
                    {
                        if (keyContent.Length >= 4 && keyContents[1].Length == 6)
                        {
                            try
                            {
                                int userid = int.Parse(keyContent);//用户ID
                                int code = int.Parse(keyContents[1]);//验证码

                                Dictionary<string, object> dic = new Dictionary<string, object>();
                                //执行存储过程【用户绑定微信发送验证码】
                                DbSession.Default.FromProc("SP_UserBindWxCode")
                                .AddInputParameter("@UserID", System.Data.DbType.String, userid)
                                .AddInputParameter("@WxCode", System.Data.DbType.String, xmlMsg.FromUserName)
                                .AddInputParameter("@ChkCode", System.Data.DbType.String, code)
                                .AddReturnValueParameter("@Return_Value", System.Data.DbType.Int32)
                                .Execute(out dic);

                                Helper.ExtLog("传入存储过程参数：userid=" + userid + ";wxcode=" + xmlMsg.FromUserName + ";chkcode=" + code);

                                if (dic.Count > 0)
                                {
                                    string result = dic["Return_Value"].ToString();//得到执行结果

                                    Helper.ExtLog("存储过程返回结果：" + result);

                                    if (result == "0")
                                    {
                                        msg = "您的微信已成功绑定猎鱼岛游戏账号，游戏账号ID：" + userid + "！";
                                        returnValue += msg;
                                    }
                                    else if (result == "1")
                                    {
                                        msg = "绑定用户失败，验证码输入有误，请重新输入。";
                                        returnValue += "用户ID不能为空";
                                    }
                                    else if (result == "2")
                                    {
                                        msg = "绑定用户失败，验证码输入有误，请重新输入。";
                                        returnValue += "微信号不能为空";
                                    }
                                    else if (result == "3")
                                    {
                                        msg = "绑定用户失败，验证码输入有误，请重新输入。";
                                        returnValue += "请确认你的游戏ID是否正确";
                                    }
                                    else if (result == "4")
                                    {
                                        msg = "绑定用户失败，请获取验证码。";
                                        returnValue += "请重新获取验证码";
                                    }
                                    else if (result == "5")
                                    {
                                        msg = "绑定用户失败，你已经绑定微信号，不能重复绑定。";
                                        returnValue += "你已经绑定微信号，不能重复绑定";
                                    }
                                    else if (result == "6")
                                    {
                                        msg = "绑定用户失败，验证码错误。";
                                        returnValue += "验证码错误";
                                    }
                                    else if (result == "7")
                                    {
                                        msg = "绑定用户失败，验证码过期,请在游戏客户端重新获取。";
                                        returnValue += "验证码过期";
                                    }
                                }
                            }
                            catch (Exception e)
                            {
                                returnValue += "出现异常" + e.ToString();
                                msg = "绑定用户失败，验证码输入有误，请重新输入。";
                            }
                        }
                        else
                        {
                            returnValue += "UserID和code长度不够。";
                            msg = "绑定用户失败，验证码输入有误，请重新输入。";
                        }
                    }
                    else
                    {
                        returnValue += "UserID和code为空！";
                        msg = "绑定用户失败，验证码输入有误，请重新输入。";
                    }
                }
                ///日志
                LogClass log = new LogClass();
                string url = "log\\" + DateTime.Now.ToString("yyyy-MM-dd") + "log.txt";
                string logContent = "用户绑定微信号结果为：" + returnValue + ",时间为：" + DateTime.Now;
                log.WriteLog(logContent, Server.MapPath(url));

                //string resxml = "<xml><ToUserName><![CDATA[" + xmlMsg.FromUserName + "]]></ToUserName><FromUserName><![CDATA[" + xmlMsg.ToUserName + "]]></FromUserName><CreateTime>" + nowtime
                //         + "</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[" + msg + "]]></Content><FuncFlag>0</FuncFlag></xml>";
                return msg;
            }
            else
            {
                return SubscribeWelcomeWord();
            }
        }

        /// <summary>
        /// 刚关注时的时候，用于欢迎词
        /// </summary>
        /// <returns></returns>
        private string SubscribeWelcomeWord()
        {
            XmlDocument doc2 = new XmlDocument();
            string url = Server.MapPath("~/Config/About.config");
            doc2.Load(url);
            XmlNode dataNode = doc2.SelectSingleNode("data");
            XmlNode greetingNode = dataNode.SelectSingleNode("Greeting");
            XmlElement xe = (XmlElement)greetingNode;
            string greetingValue = xe.GetAttribute("value").ToString();
            return greetingValue;
        }

        #endregion

        #endregion

        #region 获取access_token
        ///// <summary>
        ///// 获取access_token
        ///// </summary>
        //[HttpPost]//[HttpGet]可以通过url通过?传参
        //public JsonResult GetAccess_Token()
        //{
        //    var res = new JsonResult();
        //    var jsonText = PubBLL.GetAccess_Token(AppID, AppSecret);
        //    JObject jo = (JObject)JsonConvert.DeserializeObject(jsonText); //JObject.Parse(jsonText);//返回{"access_token":"ACCESS_TOKEN","expires_in":7200}
        //    string access_token = string.Empty;
        //    if (jo.Property("access_token") == null || jo.Property("access_token").ToString() == "")
        //    { }
        //    else access_token = jo["access_token"].ToString();

        //    Access_Token = access_token;
        //    res.Data = access_token;
        //    return res;
        //    //return Json(new { result = true, data = access_token });
        //    //return Content(Utility.ToJson(_model));
        //}
        #endregion

        #region 主动给用户发消息
        /// <summary>
        /// 主动给用户发消息（用户）,用会SetGlobalCredential方法设置的appId和appSecret来得到access_token
        /// </summary>
        /// <param name="type"></param>
        /// <param name="touser"></param>
        /// <param name="msg"></param>
        /// <returns></returns>
        //[HttpPost]
        public ActionResult SendMsg(string type, string touser, string msg)
        {
            var obj = new SendMsg();
            obj.msgtype = type;
            obj.touser = touser;
            obj.text = msg;
            var model = PubBLL.SendMsg(obj, Access_Token, null);
            var json = model.GetJSON();
            return Json(new { result = true, data = json });//正确时的返回JSON数据： {"errcode":0,"errmsg":"ok"}
        }

        #endregion

        #region 群发

        /// <summary>
        /// 根据分组进行群发
        /// </summary>
        /// <param name="mess"></param>
        /// <returns></returns>
        public SendReturnCodeModelModel SendMessByGroup(FilterMess mess)
        {
            //1.图文消息，先调用上传图文消息素材，返回媒体文件/图文消息上传后获取的唯一标识后，在调用群发接口
            //2.视频消息，此处视频的media_id需通过POST请求到下述接口特别地得到： https://file.api.weixin.qq.com/cgi-bin/media/uploadvideo?access_token=ACCESS_TOKEN ，返回媒体文件/图文消息上传后获取的唯一标识后，在调用群发接口
            //3.其他多媒体（媒体文件类型，分别有图片（image）、语音（voice）、视频（video）和缩略图（thumb）），先上传多媒体文件(公众号可调用上传多媒体文件接口来上传图片、语音、视频等文件到微信服务器，上传后服务器会返回对应的media_id),在调用群发接口
            //上传的多媒体文件有格式和大小限制，如下：
            //图片（image）: 1M，支持JPG格式
            //语音（voice）：2M，播放长度不超过60s，支持AMR\MP3格式
            //视频（video）：10MB，支持MP4格式
            //缩略图（thumb）：64KB，支持JPG格式 
            //媒体文件在后台保存时间为3天，即3天后media_id失效。 

            //传值：group_id，media_id 或者group_id，content
            return PubBLL.SendMessByGroup(mess, Access_Token);
        }

        /// <summary>
        /// 根据OpenID列表群发
        /// </summary>
        /// <param name="mess"></param>
        /// <returns></returns>
        public SendReturnCodeModelModel SendMessByUsers(FilterMess mess)
        {
            //1.图文消息，先调用上传图文消息素材，返回媒体文件/图文消息上传后获取的唯一标识后，在调用群发接口
            //2.视频消息，此处视频的media_id需通过POST请求到下述接口特别地得到： https://file.api.weixin.qq.com/cgi-bin/media/uploadvideo?access_token=ACCESS_TOKEN ，返回媒体文件/图文消息上传后获取的唯一标识后，在调用群发接口
            //3.其他多媒体（媒体文件类型，分别有图片（image）、语音（voice）、视频（video）和缩略图（thumb）），先上传多媒体文件(公众号可调用上传多媒体文件接口来上传图片、语音、视频等文件到微信服务器，上传后服务器会返回对应的media_id),在调用群发接口
            //上传的多媒体文件有格式和大小限制，如下：
            //图片（image）: 1M，支持JPG格式
            //语音（voice）：2M，播放长度不超过60s，支持AMR\MP3格式
            //视频（video）：10MB，支持MP4格式
            //缩略图（thumb）：64KB，支持JPG格式 
            //媒体文件在后台保存时间为3天，即3天后media_id失效。 

            //传值：openid（list数组），media_id 或者openid（list数组），content
            return PubBLL.SendMessByUsers(mess, Access_Token);
        }

        /// <summary>
        /// 删除群发.
        /// </summary>
        public ActionResult DeleteMess(int msgid)
        {
            var _model = PubBLL.DeleteMess(msgid, Access_Token);
            var json = _model.GetJSON();
            return Content(json);
        }

        #endregion

        #region 分组管理接口

        /// <summary>
        /// 创建分组
        /// 测试：http://localhost/weixin/CreateGroup?groupname=组1
        /// </summary>
        /// <param name="groupname"></param>
        /// <returns></returns>
        /// <remarks>
        /// access_token:调用接口凭证
        /// groupname:分组名字（30个字符以内）
        /// </remarks>
        [HttpPost]
        public JsonResult CreateGroup(string groupname)
        {
            //string body = string.Format("{\"group\":{\"name\":\"{0}\"}}", groupname);
            //string url = string.Format("https://api.weixin.qq.com/cgi-bin/groups/create?access_token={0}", Access_Token);
            //string ret = Tencent.PostAndGet.HttpPost(url, body);

            GroupInfo _model = PubBLL.CreateGroup(groupname, Access_Token);
            //var json = _model.GetJSON();
            var jsonText = string.Empty;
            if (_model.id > 0)
                jsonText = _model.name;
            //return Content(jsonText);//正确时的返回JSON数据： { "group": { "id": 107, "name": "test" } }
            return Json(new { result = true, data = jsonText + "创建成功" });
        }

        [HttpPost]
        /// <summary>
        /// 查询所有分组
        /// </summary>
        //access_token:调用接口凭证
        public ActionResult GetGroup()
        {
            //string url = string.Format("https://api.weixin.qq.com/cgi-bin/groups/get?access_token={0}", Access_Token);
            //string ret = Tencent.PostAndGet.HttpGet(url, string.Empty);

            var _model = PubBLL.GetGroups(Access_Token);
            //var json = _model.GetJSON();
            var jsonText = "[";
            if (_model.Count > 0)
            {
                foreach (var _entity in _model)
                {
                    jsonText += "{\"groupid\":\"" + _entity.id + "\",\"groupname\":\"" + _entity.name + "\"},";
                }
            }
            jsonText = jsonText.TrimEnd(',') + "]";
            //return Content(jsonText.TrimEnd(','));//正确时的返回JSON数据： {"groups": [{"id": 0, "name": "未分组", "count": 72596}, {"id": 1, "name": "黑名单", "count": 36}]}
            return Json(new { result = true, data = jsonText.TrimEnd(',') });
        }

        /// <summary>
        /// 根据ID,查询某个分组
        /// </summary>
        //access_token:调用接口凭证
        public GroupInfo GetGroupByID(int groupid)
        {
            GroupInfo groupmodel = new GroupInfo();
            //string url = string.Format("https://api.weixin.qq.com/cgi-bin/groups/get?access_token={0}", Access_Token);
            //string ret = Tencent.PostAndGet.HttpGet(url, string.Empty);

            var _model = PubBLL.GetGroups(Access_Token);
            //var json = _model.GetJSON();
            var jsonText = string.Empty;
            if (_model.Count > 0)
            {
                foreach (var _entity in _model)
                {
                    if (_entity.id == groupid)
                    {
                        groupmodel = _entity;
                        break;
                    }
                    continue;
                }
            }
            return groupmodel;//正确时的返回JSON数据： {"groups": [{"id": 0, "name": "未分组", "count": 72596}, {"id": 1, "name": "黑名单", "count": 36}]}
        }

        /// <summary>
        /// 修改分组名
        /// 测试：localhost/weixin/UpdateGroup?groupid=101&newgroupname=nihao
        /// </summary>
        [HttpPost]
        public ActionResult UpdateGroup(int groupid, string newgroupname)
        {
            //string body = string.Format("{\"group\":{\"id\":{0},\"name\":\"{1}\"}}", groupid, newgroupname);
            //string url = string.Format("https://api.weixin.qq.com/cgi-bin/groups/update?access_token={0}", Access_Token);
            //string ret = Tencent.PostAndGet.HttpPost(url, body);

            var _model = PubBLL.UpdateGroup(groupid.ToString(), newgroupname, Access_Token);
            //var json = _model.GetJSON();
            var jsonText = string.Empty;
            if (_model.errcode > 0)
                jsonText = _model.errmsg;
            else
                jsonText = "修改成功";
            //return Content(jsonText);//正确时的返回JSON数据： {"errcode":0,"errmsg":"ok"}
            return Json(new { result = true, data = jsonText });
        }

        [HttpGet]
        /// <summary>
        /// 查询用户所在分组
        /// </summary>
        //access_token:调用接口凭证
        //openid:用户的OpenID 
        public ActionResult GetUserGroup(string openid)
        {
            //string body = string.Format("{\"openid\":\"{0}\"}", openid);
            //string url = string.Format("https://api.weixin.qq.com/cgi-bin/groups/getid?access_token={0}", Access_Token);
            //string ret = Tencent.PostAndGet.HttpPost(url, body);

            var _model = PubBLL.GetUserGroup(openid, Access_Token);
            //var json = _model.GetJSON();
            var _groupmodel = GetGroupByID(_model.id);
            return Content(_groupmodel.name);//正确时的返回JSON数据： {"groupid": 102}
        }

        [HttpGet]
        /// <summary>
        /// 移动用户分组
        /// </summary>
        //access_token:调用接口凭证
        //openid:用户的OpenID
        //to_groupid:分组id
        public ActionResult MoveGroup(string openid, int to_groupid)
        {
            //string body = string.Format("{\"openid\":\"{0}\",\"to_groupid\":{1}}", openid, to_groupid);
            //string url = string.Format("https://api.weixin.qq.com/cgi-bin/groups/members/update?access_token={0}", Access_Token);
            //string ret = Tencent.PostAndGet.HttpPost(url, body);

            ReturnCodeModel _model = PubBLL.MoveGroup(openid, to_groupid.ToString(), Access_Token);
            var json = _model.GetJSON();
            var _groupmodel = GetGroupByID(to_groupid);
            return Content("移动到" + _groupmodel.name + "成功");//正确时的返回JSON数据： {"groupid": 102}
        }

        #endregion

        #region 用户信息
        [HttpPost]
        /// <summary>
        /// 获取用户基本信息(UnionID机制)
        /// </summary>
        /// <param name="openid"></param>
        /// <returns></returns>
        public JsonResult GetUserInfo(string openid)
        {
            var jsonText = PubBLL.GetUserInfo(openid, LangType.zh_CN, Access_Token);
            JObject jo = (JObject)JsonConvert.DeserializeObject(jsonText); //JObject.Parse(jsonText);
            string nickname = string.Empty;
            if (jo.Property("nickname") == null || jo.Property("nickname").ToString() == "")
            { }
            else nickname = jo["nickname"].ToString();
            return Json(new { result = true, data = nickname });
        }

        [HttpPost]
        /// <summary>
        /// 获取用户基本信息(UnionID机制)
        /// </summary>
        /// <param name="openid"></param>
        /// <returns></returns>
        public JsonResult UpdateRemark(string f_uid, string f_remark)
        {
            var jsonText = PubBLL.SetUserRemark(f_uid, f_remark, Access_Token);
            JObject jo = (JObject)JsonConvert.DeserializeObject(jsonText); //JObject.Parse(jsonText);
            string errcode = string.Empty;
            if (jo.Property("errcode") == null || jo.Property("errcode").ToString() == "")
            { }
            else errcode = jo["errcode"].ToString();
            string tempmsg = string.Empty;
            if (errcode.Equals("0"))
                tempmsg = "修改完成";
            else
                tempmsg = jo["errmsg"].ToString();
            return Json(new { result = true, data = tempmsg });
        }

        #endregion

        #region 获取关注者列表

        [HttpPost]
        /// <summary>
        /// 获取所有关注者列表
        /// </summary>
        /// <param name="appId"></param>
        /// <param name="appSecret"></param>
        /// <returns></returns>
        public JsonResult GetFollowers(string next_openid)
        {
            var _model = PubBLL.GetFollowers(Access_Token, next_openid);
            var jsonText = "[";
            if (_model.data.openid.Count > 0)
            {
                foreach (var _entity in _model.data.openid)
                {
                    jsonText += "{\"subscribeid\":\"" + _entity + "\",\"subscribename\":\"" + _entity + "\"},";
                }
            }
            jsonText = jsonText.TrimEnd(',') + "]";
            return Json(new { result = true, data = jsonText.TrimEnd(',') });
        }

        #endregion

        #region 自定义菜单
        [HttpPost]
        /// <summary>
        /// 自定义菜单创建接口
        /// </summary>
        public ActionResult CreateMenu(string type, string name, string key, string url)
        {
            //清空上一次数据
            CustomMenu._menumodel.button.Clear();
            MultiButton._model.sub_button.Clear();
            //switch (type.ToLower())
            //{
            //    case "click":
            //        CustomMenu._menumodel.button.Add(new ClickButton()
            //        {
            //            name = name,
            //            key = key,
            //            //sub_button= [ ]
            //        });
            //        break;
            //    case "view":
            //        CustomMenu._menumodel.button.Add(new ViewButton()
            //        {
            //            name = name,
            //            url = url,
            //            //sub_button= [ ]
            //        });
            //        break;
            //    case "scancode_waitmsg":
            //        CustomMenu._menumodel.button.Add(new Scancode_waitmsgButton()
            //        {
            //            name = name,
            //            key = key,
            //            //sub_button= [ ]
            //        });
            //        break;
            //    case "scancode_push":
            //        CustomMenu._menumodel.button.Add(new Scancode_pushButton()
            //        {
            //            name = name,
            //            key = key,
            //            //sub_button= [ ]
            //        });
            //        break;
            //    case "pic_sysphoto":
            //        CustomMenu._menumodel.button.Add(new Pic_sysphotoButton()
            //        {
            //            name = name,
            //            key = key,
            //            //sub_button= [ ]
            //        });
            //        break;
            //    case "pic_photo_or_album":
            //        CustomMenu._menumodel.button.Add(new Pic_photo_or_albumButton()
            //        {
            //            name = name,
            //            key = key,
            //            //sub_button= [ ]
            //        });
            //        break;
            //    case "pic_weixin":
            //        CustomMenu._menumodel.button.Add(new Pic_weixinButton()
            //        {
            //            name = name,
            //            key = key,
            //            //sub_button= [ ]
            //        });
            //        break;
            //    case "location_select":
            //        CustomMenu._menumodel.button.Add(new Location_selectButton()
            //        {
            //            name = name,
            //            key = key,
            //            //sub_button= [ ]
            //        });
            //        break;
            //}

            #region 测试
            //string menuJSON = string.Empty;
            //if (string.IsNullOrEmpty(menuJSON))
            //    menuJSON = "{\"button\":[{\"type\":\"click\",\"name\":\"今日歌曲\",\"key\":\"V1001_TODAY_MUSIC\"},{\"name\":\"菜单\",\"sub_button\":[{\"type\":\"view\",\"name\":\"视频\",\"url\":\"http://v.qq.com/\"},{\"type\":\"click\",\"name\":\"赞一下我们\",\"key\":\"V1001_GOOD\"}]}]}";
            //string url = string.Format("https://api.weixin.qq.com/cgi-bin/menu/create?access_token={0}", Access_Token);
            //string ret = Tencent.PostAndGet.HttpPost(url, menuJSON);

            var _clickmodel = new ClickButton()
            {
                name = "赞一下我们",
                key = "V1001_GOOD"
            };
            CustomMenu._menumodel.button.Add(_clickmodel);
            CustomMenu._menumodel.button.Add(new Scancode_waitmsgButton()
            {
                name = "扫码带提示",
                key = "rselfmenu_0_0",
                //sub_button= [ ]
            });
            CustomMenu._menumodel.AddViewButton(new ViewButton()
            {
                url = "http://www.baidu.com",
                name = "百度"
            });
            //添加二级菜单数组按钮
            MultiButton._model.AddPic_sysphotoButton(new Pic_sysphotoButton()
            {
                name = "系统拍照发",
                key = "rselfmenu_1_0",
                //sub_button= [ ]
            });
            CustomMenu._menumodel.button[0].sub_button = MultiButton._model.sub_button;
            #endregion
            ReturnCodeModel _objret = CreateMenu(CustomMenu._menumodel, Access_Token);
            //string menuJSON = Utility.ToJson(_objret);
            //return Content(menuJSON);//正确时的返回JSON数据： {"errcode":0,"errmsg":"ok"}
            var jsonText = string.Empty;
            if (_objret.errcode > 0)
                jsonText = _objret.errmsg;
            else
                jsonText = "创建菜单成功";
            return Json(new { result = true, data = jsonText });//正确时的返回JSON数据： {"errcode":0,"errmsg":"ok"}
        }

        /// <summary>
        /// 创建自定义菜单
        /// </summary>
        /// <param name="menu">菜单按钮集合</param>
        /// <returns></returns>
        public static ReturnCodeModel CreateMenu(CustomMenu menu, string AccessToken)
        {
            var json = menu.GetJSON();
            return PubBLL.CreateMenu(json, AccessToken);
        }

        [HttpPost]
        /// <summary>
        /// 自定义菜单查询接口，直接返回自定义菜单json字符串
        /// </summary>
        public ActionResult GetMenu()
        {
            var jsonText = PubBLL.GetMenu(Access_Token);
            //return Content(json);//返回{"menu":{"button":[{"type":"click","name":"今日歌曲","key":"V1001_TODAY_MUSIC","sub_button":[]}]}}
            return Json(new { result = true, data = jsonText });
        }

        [HttpPost]
        /// <summary>
        /// 自定义菜单删除接口
        /// </summary>
        public ActionResult DeleteMenu()
        {
            //string url = string.Format("https://api.weixin.qq.com/cgi-bin/menu/delete?access_token={0}", Access_Token);
            //string json = Tencent.PostAndGet.HttpGet(url, string.Empty);
            ////var json = Tencent.PostAndGet.HttpGet2(url);

            ReturnCodeModel _model = PubBLL.DeleteMenu(Access_Token);
            //var json = _model.GetJSON();//var _json = _model.ToString();
            //return Content(json);//返回{"errcode":0,"errmsg":"ok"}
            var jsonText = string.Empty;
            if (_model.errcode > 0)
                jsonText = _model.errmsg;
            else
                jsonText = "删除菜单成功";
            return Json(new { result = true, data = jsonText });//正确时的返回JSON数据： {"errcode":0,"errmsg":"ok"}
        }
        #endregion

        #region 生成带参数的二维码

        [HttpPost]
        /// <summary>
        /// 创建二维码ticket
        /// 测试：http://localhost/weixin/CreateTempQRCode?isTemp=true&scene_id=123
        /// </summary>
        public ActionResult CreateTempQRCode(string isTemp, int scene_id)
        {
            //string body = string.Empty;
            //if (isTemp)
            //    //创建临时二维码ticket
            //    body = "{\"expire_seconds\": 1800, \"action_name\": \"QR_SCENE\", \"action_info\": {\"scene\": {\"scene_id\": 123}}}";
            //else
            ////创建永久二维码ticket
            //    body = "{\"action_name\": \"QR_LIMIT_SCENE\", \"action_info\": {\"scene\": {\"scene_id\": 123}}}";
            //string url = string.Format(" https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token={0}", Access_Token);
            //string ret = Tencent.PostAndGet.HttpPost(url, body);

            var _model = PubBLL.CreateQRCode(bool.Parse(isTemp), scene_id, Access_Token);

            //二维码图片相对路径
            if (!string.IsNullOrEmpty(_model.ticket))
            {
                _model.imgurl = GetQRUrl(_model.ticket);
            }
            //var json = _model.GetJSON();
            return Json(new { result = true, data = _model.imgurl });//正确时的返回JSON数据： {"errcode":0,"errmsg":"ok"}
        }

        /// <summary>
        /// 通过ticket换取二维码
        /// </summary>
        /// <param name="qrcodeTicket"></param>
        /// <returns></returns>
        public string GetQRUrl(string qrcodeTicket)
        {
            ////var res = new JsonResult();
            string jsonText = PubBLL.GetQRUrl(qrcodeTicket);
            //JObject jo = (JObject)JsonConvert.DeserializeObject(jsonText); //JObject.Parse(jsonText);//返回{"access_token":"ACCESS_TOKEN","expires_in":7200}
            //string relativepath = string.Empty;
            //if (jo.Property("relativepath") == null || jo.Property("relativepath").ToString() == "")
            //{ }
            //else relativepath = jo["relativepath"].ToString();
            ////res.Data = relativepath;//图片相对路径
            return jsonText;
        }
        #endregion

        #region access_token
        public ActionResult GetToken()
        {
            var result = new ServiceResult();
            //DateTime ExpirationTime = DateTime.Now;//access_token过期时间
            //DateTime gqsj = DateTime.Now;//jsapi_ticket过期时间
            var AccessTokenModel = WeixinConfig.BaseAccessToken(WeixinType.CertServiceAccount);
            var jsapi_ticket = WeixinConfig.BaseJsApiTicket(WeixinType.CertServiceAccount).ParamValue;
            result.code = 1;
            result.msg = "成功";
            result.data = new { Access_token = AccessTokenModel.ParamValue, jsapi_ticket = jsapi_ticket, ExpirationTime = AccessTokenModel.ExpirationTime.ToString("yyyy-MM-dd HH:mm:ss") };//Unix时间戳(Unix timestamp)转换工具:http://tool.chinaz.com/Tools/unixtime.aspx

            var json = new JsonResult();
            json.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
            json.Data = result as ServiceResult;
            return json;
        }
        #endregion
        #region jsapi_ticket
        /*
         * 生成签名之前必须先了解一下jsapi_ticket，jsapi_ticket是公众号用于调用微信JS接口的临时票据。正常情况下，jsapi_ticket的有效期为7200秒，通过access_token来获取。由于获取jsapi_ticket的api调用次数非常有限，频繁刷新jsapi_ticket会导致api调用受限，影响自身业务，开发者必须在自己的服务全局缓存jsapi_ticket 。
         * 参考以下文档获取access_token（有效期7200秒，开发者必须在自己的服务全局缓存access_token）：http://mp.weixin.qq.com/wiki/15/54ce45d8d30b6bf6758f68d2e95bc627.html
         * 用第一步拿到的access_token 采用http GET方式请求获得jsapi_ticket（有效期7200秒，开发者必须在自己的服务全局缓存jsapi_ticket）：https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi 
         * {
         * "errcode":0,
         * "errmsg":"ok",
         * "ticket":"bxLdikRXVbTPdHSM05e5u5sUoXNKd8-41ZO3MhKoyN5OfkWITDGgnr2fwJ0m9E8NYzWKVZvdVtaUgWvsdshFKA",
         * "expires_in":7200
         * }
         * **/
        //[HttpPost]
        /// <summary>
        /// 获取jsapi_ticket
        /// 微信JS SDK Demo 官方案例 http://my.oschina.net/superkangning/blog/367484?fromerr=Gqr6PKLj
        /// 测试：http://localhost/weixin/GetJSApiTicket?ran=123456
        /// </summary>
        public ActionResult GetJSApiTicket(string url)
        {
            #region 生成参数
            int errcode = 0;
            var msg = string.Empty;
            DateTime gqsj = DateTime.Now;
            var jsapi_ticket = WeixinConfig.BaseJsApiTicket(WeixinType.CertServiceAccount).ParamValue;
            //微信 JS 接口签名校验工具:http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign
            var appid = "wxbd5a742342931b15";
            var noncestr = CommonHelper.RandomString();
            var timestamp = CommonHelper.UnixInter().ToString();//Pub.GetTimeStamp(DateTime.Now);
            var signature = string.Empty;
            List<string> signaturelist = new List<string>();
            if (string.IsNullOrWhiteSpace(url))
            {
                //朋友圈   from=timeline&isappinstalled=0
                //微信群   from=groupmessage&isappinstalled=0
                //好友分享 from=singlemessage&isappinstalled=0
                List<string> urllist = new List<string>();
                urllist.Add("http://h5.dianyadian.com/StoreActivity/Download/twentyd?from=singlemessage&isappinstalled=0");
                urllist.Add("http://h5.dianyadian.com/StoreActivity/Download/twentyd?from=timeline&isappinstalled=0");
                foreach (string tempurl in urllist)
                {
                    var tempsignature = string.Format("jsapi_ticket={0}&noncestr={1}&timestamp={2}&url={3}", jsapi_ticket, noncestr, timestamp, tempurl);
                    signaturelist.Add(CommonHelper.EncryptSHA1(tempsignature));
                    signature = string.Join("|", signaturelist);//如果是多个url，则用'|'连接，进行拼接
                }
            }
            else
            {
                var tempsignature = string.Format("jsapi_ticket={0}&noncestr={1}&timestamp={2}&url={3}", jsapi_ticket, noncestr, timestamp, url);
                signaturelist.Add(CommonHelper.EncryptSHA1(tempsignature));
                signature = string.Join("|", signaturelist);//如果是1个url，则不需要拼接
            }
            #endregion
            //return Json(new { result = true, msg = msg, data = new { jsapiticket = jsapi_ticket, timestamp = timestamp, noncestr = noncestr, signature = signature } });
            //return Json(new { result = true, msg = msg, data = new { jsapiticket = jsapi_ticket, timestamp = timestamp, noncestr = noncestr, signature = signature } }, JsonRequestBehavior.AllowGet);
            var json = new JsonResult();
            json.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
            json.Data = new ServiceResult() { code = 1, msg = msg, data = new { appid = appid, jsapiticket = jsapi_ticket, timestamp = timestamp, noncestr = noncestr, signature = signature } };
            return json;
        }

        [System.Web.Services.WebMethod]
        [System.Web.Script.Services.ScriptMethod(ResponseFormat = System.Web.Script.Services.ResponseFormat.Json, XmlSerializeString = false, UseHttpGet = true)]
        public void GetJSApiTickets(string url)
        {
            #region 生成参数
            int errcode = 0;
            var msg = string.Empty;
            DateTime gqsj = DateTime.Now;
            var jsapi_ticket = WeixinConfig.BaseJsApiTicket(WeixinType.CertServiceAccount).ParamValue;
            //微信 JS 接口签名校验工具:http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign
            var appid = "wxbd5a742342931b15";
            var noncestr = "1728332447";
            var timestamp = "1441540103";//Pub.GetTimeStamp(DateTime.Now);
            var signature = string.Empty;
            List<string> signaturelist = new List<string>();
            var tempsignature = string.Format("jsapi_ticket={0}&noncestr={1}&timestamp={2}&url={3}", jsapi_ticket, noncestr, timestamp, System.Web.HttpContext.Current.Server.UrlDecode(url));
            signaturelist.Add(CommonHelper.EncryptSHA1(tempsignature));
            signature = string.Join("|", signaturelist);
            #endregion
            var response = System.Web.HttpContext.Current.Response;
            response.Clear(); //清空无关信息
            response.Buffer = true; //完成整个响应后再发送
            response.Charset = "GB2312";//设置输出流的字符集-中文
            response.AppendHeader("Content-Disposition", "attachment;filename=Report.doc");//追加头信息
            response.ContentEncoding = System.Text.Encoding.GetEncoding("GB2312");//设置输出流的字符集
            response.ContentType = "text/json";

            //获取回调函数名
            var context = System.Web.HttpContext.Current.Request;
            string callback = context.QueryString["callback"];
            var jsons = "[{\"appid\":\"" + appid + "\",\"jsapiticket\":\"" + jsapi_ticket + "\",\"timestamp\":\"" + timestamp + "\",\"noncestr\":\"" + noncestr + "\",\"signature\":\"" + signature + "\",\"url\": \"" + url + "\" }]";
            response.Write(callback + "(" + jsons + ")");
            response.End();

        }

        #endregion

        #region 多媒体文件
        [HttpPost]
        /// <summary>
        /// 上传的多媒体文件有格式和大小限制，如下：
        /// 图片（image）: 1M，支持JPG格式
        /// 语音（voice）：2M，播放长度不超过60s，支持AMR\MP3格式
        /// 视频（video）：10MB，支持MP4格式
        /// 缩略图（thumb）：64KB，支持JPG格式
        /// 媒体文件在后台保存时间为3天，即3天后media_id失效。
        /// </summary>
        /// <param name="file"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public ActionResult UploadMedia(string file, string type)
        {
            string jsonText = PubBLL.UploadMedia(file, type, Access_Token);
            JObject jo = (JObject)JsonConvert.DeserializeObject(jsonText); //JObject.Parse(jsonText);
            string media_id = string.Empty;
            if (jo.Property("media_id") == null || jo.Property("media_id").ToString() == "")
            { }
            else media_id = jo["media_id"].ToString();

            //直接返回了下载的路径
            string jsonTextDownload = PubBLL.DownloadMedia(media_id, Access_Token);//下载多媒体文件
            //JObject joDownload = (JObject)JsonConvert.DeserializeObject(jsonTextDownload); //JObject.Parse(jsonText);
            //string url = joDownload["relativepath"].ToString();
            return Json(new { result = true, data = media_id + ":" + jsonTextDownload });
        }

        public static MediaInfo UploadVideoForMess(UploadVideoInfo videoInfo)
        {
            return PubBLL.UploadVideoForMess(videoInfo, Access_Token);
        }

        /// <summary>
        /// 上传图文消息素材,用于群发
        /// </summary>
        /// <param name="news"></param>
        /// <returns></returns>
        public static MediaInfo UploadArticles(Articles list)
        {
            return PubBLL.UploadArticles(list, Access_Token);
        }

        public JsonResult DownloadMedia(string media_id)
        {
            string jsonText = PubBLL.DownloadMedia(media_id, Access_Token);
            //JObject jo = (JObject)JsonConvert.DeserializeObject(jsonText); //JObject.Parse(jsonText);
            //string filepath = string.Empty;
            //if (jo.Property("filepath") == null || jo.Property("filepath").ToString() == "")
            //{ }
            //else filepath = jo["filepath"].ToString();
            return Json(new { result = true, data = jsonText });
        }

        #endregion

        #region 转换成mp3
        [HttpPost]
        public string ConvertMp3()
        {
            string oldfilepath = System.Web.HttpContext.Current.Server.MapPath(BSFConfig.DownloadFile + @"/20141119/20141119210336312377.amr");
            string newfilepath = oldfilepath.Replace(".amr", ".mp3");
            bool ret = FileHelper.ConvertMp3(oldfilepath, newfilepath);
            return string.Empty;
        }
        #endregion

    }
}